package drds.plus.rule_engine.column_value_enumerator.handler;

import drds.plus.common.model.comparative.Comparative;

import java.util.Set;

/**
 * u 部分不连续范围
 */
public abstract class PartDiscontinousRangeEnumerateHandler implements CloseIntervalColumnValueEnumerateHandler {

    /**
     * 一次自增
     */
    protected abstract Comparable getOneStep(Comparable source, Comparable atomIncreaseValue);

    /**
     * 根据不同数据的最小单位将>变为>=
     */
    protected abstract Comparative changeGreaterThanToGreaterThanOrEqual(Comparative from);

    /**
     * 根据不同数据的最小单位将<变为<=
     */
    protected abstract Comparative changeLessThanToLessThanOrEqual(Comparative to);

    /**
     * 如果输入的范围大于range.size() * atomIncrementvalue的值，那么就可以做短路优化
     *
     * @param from 只有<=情况下的form值
     * @param to   只有>=情况下的to 值
     */
    protected abstract boolean inputCloseRangeGreaterThanMaxFieldOfDifination(Comparable from, Comparable to, Integer cumulativeTimes, Comparable<?> atomIncrValue);

    public void exhaust(Comparative from, Comparative to, Integer cumulativeTime, Comparable<?> atomIncreaseValue, Set<Object> returnSet) {
        if (cumulativeTime == null || atomIncreaseValue == null) {
            throw new IllegalArgumentException("当原子增参数或叠加参数为空时，不支持在sql中使用范围选择，如id>? and id<?");
        }
        from = changeGreaterThanToGreaterThanOrEqual(from);
        to = changeLessThanToLessThanOrEqual(to);

        Comparable fromComparable = from.getValue();
        Comparable toComparable = to.getValue();

        if (inputCloseRangeGreaterThanMaxFieldOfDifination(fromComparable, toComparable, cumulativeTime, atomIncreaseValue)) {
            // 如果所取得范围大于非连续函数的一个变动周期。直接断路掉,并且全取
            if (returnSet != null) {
                exhaust(from, cumulativeTime, atomIncreaseValue, returnSet);
                return;
            } else {
                throw new IllegalArgumentException("待写入的参数set为null");
            }
        }

        if (fromComparable.compareTo(toComparable) == 0) {
            // 如果转变为>=和<=得情况下，俩值相等了，那么直接返回。
            returnSet.add(fromComparable);
            return;
        }

        int rangeSize = cumulativeTime;
        returnSet.add(fromComparable);
        Comparable enumedFoD = fromComparable;
        for (int i = 0; i < rangeSize; i++) {
            enumedFoD = getOneStep(enumedFoD, atomIncreaseValue);
            int compareResult = enumedFoD.compareTo(toComparable);
            if (compareResult == 0) {
                // 枚举值等于to的值，简单的把to的值放到枚举数列里。返回
                returnSet.add(toComparable);
                return;
            } else if (compareResult > 0) {
                // 枚举值大于to得值,按月分库的情况下也需要把最后一个月加上，其他情况会多算一个库
                // 这样做，在最后一天的时候会有可能出现两个值，第一个值是由from自增出现的值，第二个是由to产生的值。规则引擎多算一次，但为了保证正确暂时先这样写
                // trace: http://jira.taobao.ali.com/browse/TDDL-38
                returnSet.add(toComparable);
                return;
            } else {
                // 枚举小于to的值,添加枚举到定义域
                returnSet.add(enumedFoD);

            }
        }

    }
}
